/*
 * Copyright 2008-2009 ArtisanLogic.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.artisanlogic.jingo.assembler;

import static com.artisanlogic.io.Utils.readContent;
import static com.artisanlogic.lang.Utils.requireParameter;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import com.artisanlogic.jingo.parser.Handler;
import com.artisanlogic.jingo.parser.Parser;

// =====================================================================================================================
// Assembler.java                                                                                Created on Jan 27, 2009
// ---------------------------------------------------------------------------------------------------------------------
/**
 * This class assembles an entire dependency graph of Jingo modules into a transitive dependency-ordered, single-source 
 * collection of modules.
 * 
 * @author john@artisanlogic.com
 * @author sean@artisanlogic.com
 * @since 0.9-Beta
 */
// =====================================================================================================================
public class Assembler implements Handler {
  
  // -------------------------------------------------------------------------------------------------------------------
  // private instance fields
  // -------------------------------------------------------------------------------------------------------------------

  private final UrlMappingStrategy urlMapper;

  private final PrintWriter writer;

  private final Parser parser;

  private final FileHandler fileHandler;

  private Set<Dependency> resolved = new TreeSet<Dependency>();

  // -------------------------------------------------------------------------------------------------------------------
  // constructors
  // -------------------------------------------------------------------------------------------------------------------
  
  /**
   * This constructor creates a new Assembler with the specified values for the urlMapper, output and fileHandler 
   * properties.
   *
   * @param urlMapper This parameter holds the URL mapping strategy to be used to map repository prefixes to actual 
   *  universal resource locators.
   * @param output This parameter holds the OutputStream that the single-source assembly should be written to.
   * @param fileHandler This parameter holds the FileHandler implementation that the assembler will delegate to if/when 
   *  it encounters nested Jingo module declarations.
   */
  public Assembler(UrlMappingStrategy urlMapper, Parser parser, OutputStream output, FileHandler fileHandler) {
    requireParameter("urlMapper", urlMapper);
    this.urlMapper = urlMapper;
    requireParameter("parser", parser);
    this.parser = parser;
    requireParameter("output", output);
    this.writer = new PrintWriter(output);
    requireParameter("fileHandler", fileHandler);
    this.fileHandler = fileHandler;
  }

  // -------------------------------------------------------------------------------------------------------------------
  // public instance methods
  // -------------------------------------------------------------------------------------------------------------------
  
  /* (non-Javadoc)
   * @see com.artisanlogic.jingo.parser.Handler#handleDependencies(int, java.util.SortedSet)
   */
  public void handleDependencies(int depth, SortedSet<Dependency> dependencies) {
    if(depth > 1) {
      fileHandler.handleDependencies(depth, dependencies);
      return;
    }
    for(Dependency dependency : dependencies) {
      if(!resolved.contains(dependency)) {
        resolved.add(dependency);
        String source = readContent(urlMapper.map(dependency));
        parser.parse(source, this, dependency.getRepository());
        writer.println(source);
        writer.flush();
      }
    }
  }

}
